package com.flowable.modules.rest.service;

import com.flowable.modules.modeler.handler.MultiInstanceHandler;
import com.flowable.modules.rest.utils.CreateChildShape;
import com.flowable.modules.rest.utils.SnowFlakeUtil;
import com.flowable.modules.rest.utils.TimeUtil;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.IdentityLinkInfo;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.ui.common.security.SecurityUtils;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.model.ModelRepresentation;
import org.flowable.ui.modeler.repository.ModelRepository;
import org.flowable.ui.modeler.serviceapi.ModelService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

import static com.flowable.modules.rest.utils.TimeUtil.DATE_TIME_PATTERN;
import static com.flowable.modules.rest.utils.TimeUtil.stringToDate;

@Service
public class FlowableService {

    @Resource
    private TaskService taskService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private HistoryService historyService;

    @Resource
    private ModelService modelService;

    @Resource
    private ModelRepository modelRepository;

    /**
     * 启动流程
     * @param processDefinitionKey
     * @param userId
     * @return
     */
    public ProcessInstance start(String processDefinitionKey, String businessKey, String userId) {
        Map<String, Object> variables = new HashMap<>();
        //允许执行跳过表达式
//        variables.put("_ACTIVITI_SKIP_EXPRESSION_ENABLED", true);

        /* 此处传入el替换对象实例，用于${el.function(arg)}表达式的执行 */
        variables.put("multiInstanceHandler",new MultiInstanceHandler());

        //第一步用，发起人为第一步审批人
        variables.put("userId",userId);

        //将发起人作为节点第一步时使用
        Authentication.setAuthenticatedUserId(userId);

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        Authentication.setAuthenticatedUserId(null);

        List<Task> list = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).list();
        return processInstance;
    }

    /**
     * 获取流程实例
     * @param processInstanceId
     * @return
     */
    public ProcessInstance get(String processInstanceId){
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        return processInstance;
    }

    /**
     * 根据实例id获取task
     * @param processInstanceId
     * @return
     */
    public List<Task> listTask(String processInstanceId) {
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        return tasks;
    }

    /**
     *
     * @param taskId
     * @return
     */
    public Task getTask(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        return task;
    }

    /**
     * 任务签收
     * @param taskId
     * @param variables
     */
    public void complete(String taskId, Map<String, Object> variables) {
        taskService.complete(taskId, variables);
    }

    public void move(Task task, String activityName) {
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(
                        Arrays.asList(task.getTaskDefinitionKey()),
                        activityName)
                .changeState();
    }


    public List<EndEvent> getEnd(String processDefinitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        List<EndEvent> endEvents = bpmnModel.getProcesses().stream().flatMap(v->v.findFlowElementsOfType(EndEvent.class).stream()).collect(Collectors.toList());
        return endEvents;
    }

    public FlowElement getFlowElement(Task task) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionId());
        return flowElement;
    }


    public Map<String, Object> getVariables(String taskId) {
        Map<String, Object> variables = taskService.getVariables(taskId);
        return variables;
    }

    public  List<String> getCandidateUsers(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).includeIdentityLinks().singleResult();
        List<? extends IdentityLinkInfo> linkInfos = task.getIdentityLinks();
        List<String> candidateUsers = linkInfos.stream().filter(v -> "candidate".equals(v.getType())).map(IdentityLinkInfo::getUserId)
                .filter(StringUtils::isNotBlank).collect(Collectors.toList());
        return candidateUsers;
    }

    public List<String> getCandidatGroups(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).includeIdentityLinks().singleResult();
        List<? extends IdentityLinkInfo> linkInfos = task.getIdentityLinks();
        List<String> candidateUsers = linkInfos.stream().filter(v -> "candidate".equals(v.getType())).map(IdentityLinkInfo::getGroupId)
                .filter(StringUtils::isNotBlank).collect(Collectors.toList());
        return candidateUsers;
    }

    /**
     * 获取待办列表
     * @param userId
     * @param roles
     * @return
     */
    public List<Map> getToDoList(String userId, List<String> roles,int pageNo,int pageSize) {
        List<Map> mapList = getToDoListDetail(userId, roles);
        mapList = setPageByList(mapList,pageSize,pageNo);
        return mapList;
    }

    /**
     * 获取待办数量
     * @param userId
     * @param roles
     * @return
     */
    public Integer getToDoCount(String userId, List<String> roles) {
        List<Map> toDoListDetail = getToDoListDetail(userId, roles);
        if(!CollectionUtils.isEmpty(toDoListDetail)){
            return toDoListDetail.size();
        }
        return 0;
    }

    /**
     * 获取待办列表实现
     * @param userId
     * @param roles
     * @return
     */
    public List<Map> getToDoListDetail(String userId,List<String> roles) {
        TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
        if(!CollectionUtils.isEmpty(roles)) {
            taskQuery.taskCandidateGroupIn(roles);
        }

        List<Task> taskList = taskQuery.active().orderByTaskId().desc().list();

        //此处清洗不能处理会签任务本人已签的情况，需将分页处理置后
        List<Task> list = removeDuplicateTask(taskList);

        List<Map> mapList = new LinkedList<>();
        String businessKey = null;
        for (Task task : list) {
            Map stepMsgList = getStepMsgList(task.getProcessDefinitionId(),task.getProcessInstanceId(),task.getId());
            if(StringUtils.isEmpty(businessKey)||!stepMsgList.get("businessKey").toString().equals(businessKey)) {
                businessKey = stepMsgList.get("businessKey").toString();
                String taskId = stepMsgList.get("taskId").toString();
                //获取剩余待办
                Task task1 = taskService.createTaskQuery().taskId(taskId).singleResult();
                List<Task> lastStep = isLastStep(task1.getProcessInstanceId());

                //会签情况下确认该步骤本人是否签过
                boolean hasSign = false;

                List<Map> aa = (List) stepMsgList.get("taskList");
                for (Map map : aa) {
                    //未办结又为会签情况下
                    if("3".equals(map.get("deal")) && "1".equals(map.get("counterSignState"))) {
                        List<Map> bb = (List<Map>) map.get("counterSignUsers");
                        if(!CollectionUtils.isEmpty(bb)) {
                            for (Map map1 : bb) {
                                if(!hasSign){
                                    hasSign = userId.equals(map1.get("assignee")) && !"3".equals(map1.get("deal"));
                                }
                            }
                        }
                    }
                }

                if(hasSign) {
                    continue;
                } else {
                    stepMsgList.put("taskId",lastStep.get(0).getId());
                    mapList.add(stepMsgList);
                }

            }
        }
        return mapList;
    }

    /**
     * 获取发起列表
     * @param userId
     * @param pageSize
     * @param pageNo
     * @return
     */
    public List<Map> getApplyList(String userId,int pageSize,int pageNo){
        List<HistoricProcessInstance> historicProcessInstanceList = historyService.createHistoricProcessInstanceQuery()
                .orderByProcessInstanceStartTime().desc().startedBy(userId).listPage((pageNo-1)*pageSize,pageSize);
        List<Map> mapList = new ArrayList();
        for (HistoricProcessInstance historicProcessInstance : historicProcessInstanceList) {
            Map stepMsgList = getStepMsgList(historicProcessInstance.getProcessDefinitionId(), historicProcessInstance.getId(), historicProcessInstance.getId());
            mapList.add(stepMsgList);
        }
        return mapList;
    }

    /**
     * 获取发起列表
     * @param userId
     * @return
     */
    public Integer getApplyCount(String userId){
        List<HistoricProcessInstance> historicProcessInstanceList = historyService.createHistoricProcessInstanceQuery()
                .orderByProcessInstanceStartTime().desc().startedBy(userId).list();
        if(!CollectionUtils.isEmpty(historicProcessInstanceList)){
            return historicProcessInstanceList.size();
        }
        return 0;
    }

    /**
     * 获取审批列表
     * @param userId
     * @return
     */
    public List<Map> getApprovalList(String userId,int pageSize,int pageNo) {
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                .taskInvolvedUser(userId).orderByHistoricTaskInstanceEndTime().desc().list();

        historicTaskInstanceList = removeDuplicateHisTask(historicTaskInstanceList);
        historicTaskInstanceList = setPageByList(historicTaskInstanceList,pageSize,pageNo);

        List<Map> mapList = new ArrayList();
        for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList) {
            Map stepMsgList = getStepMsgList(historicTaskInstance.getProcessDefinitionId(), historicTaskInstance.getProcessInstanceId(), historicTaskInstance.getId());
            mapList.add(stepMsgList);
        }
        return mapList;
    }

    /**
     * 获取审批条数（以流程整体为对象）
     * @param userId
     * @return
     */
    public Integer getApprovalCount(String userId){
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().finished().taskInvolvedUser(userId).orderByHistoricTaskInstanceEndTime().desc().list();
        if(!CollectionUtils.isEmpty(historicTaskInstanceList)){
            return removeDuplicateHisTask(historicTaskInstanceList).size();
        }
        return 0;
    }

    /**
     * 根据业务id获取流程详情
     * @param businessKey
     * @return
     */
    public Map getApprovalDetail(String businessKey){
        List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).list();
        if(CollectionUtils.isEmpty(taskList)){
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
//            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
            return getStepMsgList(historicProcessInstance.getProcessDefinitionId(),historicProcessInstance.getId(),historicProcessInstance.getId());
        }
        return getStepMsgList(taskList.get(0).getProcessDefinitionId(), taskList.get(0).getProcessInstanceId(), taskList.get(0).getId());
//        for (Task task : taskList) {
//            Map stepMsgList = getStepMsgList(task.getProcessDefinitionId(), task.getProcessInstanceId(), task.getId());
//            System.out.println(stepMsgList);
//        }
    }

    /**
     * 管理员查看全部审批
     * @return
     */
    public List<Map> getAdminTaskList(int pageSize,int pageNo){
        List<HistoricProcessInstance> historicProcessInstanceList = historyService.createHistoricProcessInstanceQuery().orderByProcessInstanceStartTime().desc().listPage((pageNo-1)*pageSize,pageSize);

        List<Map> mapList = new ArrayList();
        for (HistoricProcessInstance historicProcessInstance : historicProcessInstanceList) {
            Map stepMsgList = getStepMsgList(historicProcessInstance.getProcessDefinitionId(), historicProcessInstance.getId(), historicProcessInstance.getId());
            mapList.add(stepMsgList);
        }
        return mapList;
    }

    /**
     * 根据模型id部署流程实例
     * @param model
     * @return
     * @throws Exception
     */
    public String deploymentProcessDefinitionFromUIModel(Model model) {
        BpmnModel bpmnModel = modelService.getBpmnModel(model);
        List<Deployment> test = repositoryService.createDeploymentQuery().deploymentName(model.getName()).list();

        if(CollectionUtils.isEmpty(test)) {
            Deployment deployment = repositoryService.createDeployment()
                    .name(model.getName())
                    .addBpmnModel(model.getKey() + ".bpmn", bpmnModel).deploy();
            //部署ID
            return deployment.getId();
        } else {
            //删除模型实例
            /*repositoryService.deleteDeployment(test.get(0).getId());*/
            return test.get(0).getId();
        }
    }

    /**
     * 销毁流程实例，级联全部销毁
     * @param model
     */
    public void deploymentDestroy(Model model) {
        List<Deployment> list = repositoryService.createDeploymentQuery().deploymentName(model.getName()).list();
        for (Deployment deployment : list) {
            repositoryService.deleteDeployment(deployment.getId(),true);
        }
    }

    /**
     * 根据modelKey获取ui的model
     * @param modelKey
     * @return
     */
    public List<Model> getModelByKey(String modelKey) {

        //依据act_de_model.name字段匹配
        List<Model> byModelTypeAndFilter = modelRepository.findByKeyAndType(modelKey,0);
        return byModelTypeAndFilter;
    }

    /**
     * 送下一步
     * @param taskId
     * @param userId
     * @param comment
     * @param flowstate
     */
    public Map sendNextTaskId(String taskId, String userId, String comment, int flowstate) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        return sendNext(task, userId, comment, flowstate);
    }

    public Map sendNextProcInstId(String procInstId, String userId, String comment, int flowstate) {
        Task task = taskService.createTaskQuery().processInstanceId(procInstId).singleResult();
        return sendNext(task, userId, comment, flowstate);
    }

    public Map sendNextBusinessKey(String businessKey, String userId, String comment, int flowstate) {
        Task task = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).singleResult();
        return sendNext(task, userId, comment, flowstate);
    }

    public Map sendNext(Task task, String userId, String comment, int flowstate) {
        //审批意见
        Authentication.setAuthenticatedUserId(userId);
        taskService.addComment(task.getId(), task.getProcessInstanceId(), comment);
        taskService.addComment(task.getId(),task.getProcessInstanceId(),"opinion",flowstate+"");

        Map<String, Object> variables = new HashMap<>();
        variables.put("flag",flowstate);

        //todo
        taskService.complete(task.getId(), variables);

        //获取步骤defKey用于判断是否同一步骤会签中
        String taskDefinitionKey = task.getTaskDefinitionKey();

        Map map = new HashMap(2);
        //会签时会同一步会产生多个task
        List<Task> lastStep = isLastStep(task.getProcessInstanceId());
        List<Map> taskMapList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(lastStep)) {

            //如为执行会签并行任务时直接跳过
            if(!taskDefinitionKey.equals(lastStep.get(0).getTaskDefinitionKey())) {
                //当会签时，手动分配审批人和task的关系，会签步骤本身不校验会签人信息，仅对taskId进行判断
                if(lastStep.size()>1){
                    List<String> candidateUsers = getCandidateUsers(lastStep.get(0).getId());
                    for (int i = 0; i < lastStep.size(); i++) {
                        Map taskMap = new HashMap();
                        taskMap.put("userIds", Arrays.asList(candidateUsers.get(i)));
                        taskMap.put("groups",new ArrayList<>());
                        taskMap.put("taskId",lastStep.get(i).getId());
                        taskMap.put("scheduledState",lastStep.get(i).getDueDate()==null?"0":"1");
                        taskMapList.add(taskMap);
                    }
                } else {
                    Map taskMap = new HashMap();
                    List<String> candidateUsers = getCandidateUsers(lastStep.get(0).getId());
                    List<String> candidatGroups = getCandidatGroups(lastStep.get(0).getId());
                    taskMap.put("userIds",candidateUsers);
                    taskMap.put("groups",candidatGroups);
                    taskMap.put("taskId",lastStep.get(0).getId());
                    taskMap.put("scheduledState",lastStep.get(0).getDueDate()==null?"0":"1");
                    taskMapList.add(taskMap);
                }
            }

            map.put("isLastStep","0");
            map.put("tasks",taskMapList);
        } else {
            map.put("tasks",taskMapList);

            Map stepMsgList = getStepMsgList(task.getProcessDefinitionId(), task.getProcessInstanceId(), task.getId());

            List<Map> taskList = (List<Map>) stepMsgList.get("taskList");
            String lastStepFlag = "1";
            //
            for (Map map1 : taskList) {
                if("2".equals(map1.get("deal"))){
                    lastStepFlag = "2";
                }
            }

            map.put("isLastStep",lastStepFlag);
        }

        return map;

    }

    /**
     * 获取流程步骤完整信息（组合未审批和已审批）
     * @param procDefId
     * @param procInstId
     * @param taskId
     * @return
     */
    public Map getStepMsgList(String procDefId, String procInstId, String taskId){
        List<StepMsg> processFlowElement = getProcessFlowElement(procDefId);
        List<StepMsg> allByTask = getAllByTask(procInstId);

        Map map = new HashMap();
        List list = new ArrayList();

        String mainDeal = "1";
        for (int i = 0; i < processFlowElement.size(); i++) {
            Map taskMap = new HashMap();
            StepMsg flowElement = processFlowElement.get(i);
            String deal = null;
            List usersList = new ArrayList();
            List groupsList = new ArrayList();

            //会签标识
            String countersignState = flowElement.countersignState;
            //会签判断时使用用户
            List<String> users = flowElement.users;
            List<String> groups = flowElement.groups;

            //根据审批第一步发起的信息获取是否完结
            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(allByTask.get(0).taskId).finished().singleResult();
            List<Task> lastStep = isLastStep(historicTaskInstance.getProcessInstanceId());

            if(i >= allByTask.size()) {
                deal = "3";

                for (String user : users) {
                    Map counterSignUserMap = new HashMap();
                    counterSignUserMap.put("deal","3");
                    counterSignUserMap.put("dealTime", "");
                    counterSignUserMap.put("assignee",user);
                    usersList.add(counterSignUserMap);
                }

                for (String group : groups) {
                    Map counterSignUserMap = new HashMap();
                    counterSignUserMap.put("assignee",group);
                    groupsList.add(counterSignUserMap);
                }

            } else {
                StepMsg stepMsg = allByTask.get(i);
                List<SignUser> counterSignUsers = stepMsg.counterSignUsers;

                //将该审批步骤中全部审批人和已签进行遍历，获取该步审批全部情况
                if(!CollectionUtils.isEmpty(users)) {
                    for (String user : users) {
                        deal = "3";
                        String dealTime = "";
                        for (SignUser counterSignUser : counterSignUsers) {
                            if(user.equals(counterSignUser.userId)) {
                                String dealSign = counterSignUser.dealSign;
                                if(!"2".equals(deal)){
                                    if("2".equals(dealSign) ) {
                                        deal = "2";
                                    } else {
                                        deal = "1";
                                    }
                                }

                                dealTime = TimeUtil.dateToString(counterSignUser.dealTime,DATE_TIME_PATTERN);
                            }
                        }

                        Map counterSignUserMap = new HashMap();
                        counterSignUserMap.put("deal",deal);
                        counterSignUserMap.put("dealTime", dealTime);
                        counterSignUserMap.put("assignee",user);
                        usersList.add(counterSignUserMap);
                    }
                } else {
                    for (SignUser counterSignUser : counterSignUsers) {
                        String dealSign = counterSignUser.dealSign;
                        if(!"2".equals(deal)){
                            if("2".equals(dealSign) ) {
                                deal = "2";
                            } else {
                                deal = "1";
                            }
                        }

                        Map counterSignUserMap = new HashMap();
                        counterSignUserMap.put("deal",deal);
                        counterSignUserMap.put("dealTime", TimeUtil.dateToString(counterSignUser.dealTime,DATE_TIME_PATTERN));
                        counterSignUserMap.put("assignee",counterSignUser.userId);
                        usersList.add(counterSignUserMap);
                    }
                }


                //发起步骤标识状态为提交
                if(i == 0) {
                    deal = "0";
                    for (SignUser counterSignUser : counterSignUsers) {
                        String dealSign = counterSignUser.dealSign;
                        if(!"2".equals(deal)){
                            if("2".equals(dealSign) ) {
                                deal = "2";
                            } else {
                                deal = "1";
                            }
                        }

                        Map counterSignUserMap = new HashMap();
                        counterSignUserMap.put("deal",deal);
                        counterSignUserMap.put("dealTime", TimeUtil.dateToString(counterSignUser.dealTime,DATE_TIME_PATTERN));
                        counterSignUserMap.put("assignee",counterSignUser.userId);
                        usersList.add(counterSignUserMap);
                    }
                }

                for (String group : groups) {
                    Map counterSignUserMap = new HashMap();
                    counterSignUserMap.put("assignee",group);
                    groupsList.add(counterSignUserMap);
                }

                //该步为会签且签名人数少于待签人数则判断该步未完成
                if("1".equals(countersignState) && users.size() != counterSignUsers.size()) {
                    //该步骤未全部审批完
                    deal = "3";
                }
            }

            //获取主流程审批状态
            if("2".equals(deal)) {
                mainDeal = "2";
            }
            if(!"2".equals(mainDeal)) {
                if(i == processFlowElement.size()-1 && "3".equals(deal)) {
                    mainDeal = "3";
                }
            }

            taskMap.put("deal",deal);
            taskMap.put("taskStepName",flowElement.stepName);
            taskMap.put("users",usersList);
            taskMap.put("groups",groupsList);
            taskMap.put("counterSignState",flowElement.countersignState);
//            taskMap.put("taskId",taskId);

            list.add(taskMap);
        }

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId).singleResult();
        String businessKey;
        if(processInstance == null){
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInstId).singleResult();
            businessKey = historicProcessInstance.getBusinessKey();
        } else {
            businessKey = processInstance.getBusinessKey();
        }
        map.put("businessKey",businessKey);
        map.put("taskList",list);
        map.put("taskId",taskId);
        map.put("deal",mainDeal);

        return map;
    }

    /**
     * 根据流程实例id获取流程模型list
     * @param processDefId
     */
    public List<StepMsg> getProcessFlowElement(String processDefId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
                processDefinitionId(processDefId).active().orderByProcessDefinitionVersion().desc().singleResult();
        BpmnModel model = repositoryService.getBpmnModel(processDefinition.getId());
        List<StepMsg> list = new ArrayList<>();
        if (model != null) {
            Collection<FlowElement> flowElements = model.getMainProcess().getFlowElements();
            for (FlowElement e : flowElements) {
                if (e instanceof UserTask) {
                    list.add(new StepMsg(e.getName(),((UserTask) e).getCandidateUsers(),((UserTask) e).getCandidateGroups(),((UserTask) e).getLoopCharacteristics() == null?"0":"1",((UserTask) e).getDueDate() == null?"0":"1"));
                }
            }
        }
        return list;
    }

    /**
     * 根据json创建模型
     * @param name
     * @param description
     * @param modelType
     * @param editorJson
     * @return
     */
    public Model createNewModel(String name, String description, Integer modelType, String editorJson) {
        ModelRepresentation model = new ModelRepresentation();
        model.setName(name);
        model.setDescription(description);
        model.setKey(name);
        model.setModelType(modelType);
//        editorJson = getModelJson(name);
        return this.modelService.createModel(model, editorJson, SecurityUtils.getCurrentUserObject());
    }

    /**
     * 创建自定义模型
     * @param modelName
     * @param steps
     * @return
     */
    public Model createCustomModel(String modelName, List<Map> steps) {
        List<StepMsg> list = new ArrayList<>(steps.size());
        for (Map step : steps) {
            String stepName = step.get("stepName").toString();
            String countersignState = step.get("countersignState").toString();
            String scheduledState = step.get("scheduledState").toString();
            List<String> groups = (List) step.get("groups");
            List<String> users = (List) step.get("users");
            list.add(new StepMsg(stepName,users,groups,countersignState,scheduledState));
        }

        String modelJson = getModelJson(modelName, list);
        return createNewModel(modelName,"",0,modelJson);
    }

    /**
     * 判断流程是否完结
     * @param instId
     * @return
     */
    public List<Task> isLastStep(String instId) {
        return taskService.createTaskQuery().processInstanceId(instId).list();
    }

    public static void main(String[] args) {

        Map map = new HashMap();
        List steps = new ArrayList();
        for (int i = 0; i < 2; i++) {
            Map step = new HashMap();

            step.put("taskId","任务id"+(i+1));
            step.put("businessKey","业务id"+(i+1));

            List taskList = new ArrayList();
            for (int j = 0; j < 2; j++) {
                Map task = new HashMap();
                List counterSignUsers = new ArrayList();
                Map counterSignUser = new HashMap();
                counterSignUser.put("assignee","用户id");
                counterSignUser.put("deal","1(通过)/2(不通过)3/(未审批)");
                counterSignUser.put("dealTime","审批时间yyyy-MM-dd hh:mm:ss");
                counterSignUsers.add(counterSignUser);

                task.put("counterSignUser",counterSignUser);
                task.put("taskStepName","该步审批名称");
                task.put("deal","0(提交)/1(通过)/2(不通过)/3(未审批)");

                taskList.add(task);
            }

            step.put("taskList",taskList);
            steps.add(step);
        }

        map.put("steps",steps);

        String s = new Gson().toJson(map);
        System.out.println(s);

    }

    /**
     * 根据步骤信息创建模型json
     * @param name
     * @param stepMsgList
     * @return
     */
    public String getModelJson(String name, List<StepMsg> stepMsgList) {

        Map jsonMap = new HashMap();

        jsonMap.put("modelId",new SnowFlakeUtil(1,1).nextId());

        Map bounds = new HashMap();
        Map lowerRight = new HashMap();
        lowerRight.put("x",1200);
        lowerRight.put("y",1050);
        bounds.put("lowerRight",lowerRight);
        Map upperLeft = new HashMap();
        upperLeft.put("x",0);
        upperLeft.put("y",0);
        bounds.put("upperLeft",upperLeft);
        jsonMap.put("bounds",bounds);

        Map properties = new HashMap();
        //流程名称
        properties.put("process_id",name);
        properties.put("name",name);
        //
        properties.put("documentation","");
        properties.put("process_author","admin");
        properties.put("process_version","");
        properties.put("process_namespace","http://www.flowable.org/processdef");
        properties.put("process_historylevel","");
        properties.put("isexecutable",true);
        properties.put("dataproperties","");
        properties.put("executionlisteners","");
        properties.put("eventlisteners","");
        properties.put("signaldefinitions","");
        properties.put("messagedefinitions","");
        properties.put("escalationdefinitions","");
        properties.put("process_potentialstarteruser","");
        properties.put("process_potentialstartergroup","");
        properties.put("iseagerexecutionfetch",false);
        jsonMap.put("properties",properties);

        Map stencil = new HashMap();
        stencil.put("id","BPMNDiagram");
        jsonMap.put("stencil",stencil);

        Map stencilset = new HashMap();
        stencilset.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");
        stencilset.put("url","../editor/stencilsets/bpmn2.0/bpmn2.0.json");
        jsonMap.put("stencilset",stencilset);

        List childShapes = new ArrayList();
        for (int i = 0; i < stepMsgList.size(); i++) {
            if(i == 0) {
                Map startEvent = CreateChildShape.createStartEvent();
                Map finishEvent = CreateChildShape.createFinishEvent(stepMsgList.size());
                Map endEvent = CreateChildShape.createEndEvent(stepMsgList.size());
                Map startFlowSequence = CreateChildShape.createStartFlowSequence();
                Map finishFlowSequence = CreateChildShape.createFinishFlowSequence(stepMsgList.size());
                childShapes.add(startEvent);
                childShapes.add(finishEvent);
                childShapes.add(endEvent);
                childShapes.add(startFlowSequence);
                childShapes.add(finishFlowSequence);
            }

            StepMsg sm = stepMsgList.get(i);
            String stepName = sm.stepName;
            List<String> groups = sm.groups;
            List<String> users = sm.users;
            //会签标识
            String countersignState = sm.countersignState;
            //定时调度标识
            String scheduledState = sm.scheduledState;

            boolean isLastStep = false;

            if(i == stepMsgList.size()-1) {
                isLastStep = true;
            }

            Map userTask = CreateChildShape.createUserTask(i + 1, stepName, isLastStep, groups, users,"1".equals(countersignState),"1".equals(scheduledState));
            childShapes.add(userTask);
            Map endFlowSequence = CreateChildShape.createEndFlowSequence(i + 1);
            childShapes.add(endFlowSequence);
            Map taskFlowSequence = CreateChildShape.createTaskFlowSequence(i + 1);
            if (taskFlowSequence != null) {
                childShapes.add(taskFlowSequence);
            }
        }

        jsonMap.put("childShapes",childShapes);

        return new Gson().toJson(jsonMap);
    }

    /**
     * 流程审批步骤信息类
     */
    public class StepMsg {
        String stepName;
        List<String> users;
        List<String> groups;
        String countersignState;

        List<SignUser> counterSignUsers;
        String dealSign;
        String taskId;
        String scheduledState;


        public StepMsg(String stepName,String users, String groups) {
            this.stepName = stepName;

            List<String> userList = new ArrayList<>();
            if(StringUtils.isNotEmpty(users)) {
                String[] split = users.split("\\|");
                for (String s : split) {
                    userList.add(s);
                }
            }
            this.users = userList;

            List<String> groupList = new ArrayList<>();
            if(StringUtils.isNotEmpty(groups)) {
                String[] split = groups.split("\\|");
                for (String s : split) {
                    groupList.add(s);
                }
            }
            this.groups = groupList;
        }

        public StepMsg(String stepName, List<String> users, List<String> groups, String countersignState, String scheduledState) {
            this.stepName = stepName;
            this.users = users;
            this.groups = groups;
            this.countersignState = countersignState;
            this.scheduledState = scheduledState;
        }

        public StepMsg() {
        }
    }

    /**
     * 流程审批用户信息类
     */
    public class SignUser implements Serializable {
        private static final long serialVersionUID = 1L;

        String userId;
        Date dealTime;
        String dealSign;
        String comment;

        public SignUser(String userId, Date dealTime, String dealSign) {
            this.userId = userId;
            this.dealTime = dealTime;
            this.dealSign = dealSign;
        }

        public SignUser() {
        }
    }

    /**
     * 获取办结和当前待办步骤的全部历史task记录
     * @param processInstId
     */
    public List<HistoricTaskInstance> getHisTaskList(String processInstId) {

        List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstId);

        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstId).includeIdentityLinks().orderByTaskCreateTime().asc().list();
        return list;
    }


    /**
     * 获取处理后的审批意见
     * @param processInstId
     * @return
     */
    public List<StepMsg> getAllByTask(String processInstId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstId).singleResult();
        String processDefinitionId;
        if(processInstance == null){
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstId).singleResult();
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstId);


        // TaskName （taskId,List<Comment>） commentTaskDefIdMap
        Map<String,Map<String,List<Comment>>> commentTaskDefKeyMap = new LinkedHashMap<>();
        // TaskName List<Comment>
        Map<String,List<Comment>> taskCommentListMap = new HashMap<>();
        List<Comment> commentList = new ArrayList<>();


        if(!CollectionUtils.isEmpty(processInstanceComments)){
            for (int i = processInstanceComments.size() - 1; i >= 0; i--) {
                Comment processInstanceComment = processInstanceComments.get(i);
                HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(processInstanceComment.getTaskId()).finished().singleResult();
                String taskInstanceName = historicTaskInstance.getName();
                if(commentTaskDefKeyMap.get(taskInstanceName) == null) {
                    taskCommentListMap = new HashMap<>();
                } else {
                    taskCommentListMap = commentTaskDefKeyMap.get(taskInstanceName);
                }
                if(taskCommentListMap.get(processInstanceComment.getTaskId()) == null) {
                    commentList = new ArrayList<>();
                } else {
                    commentList = taskCommentListMap.get(processInstanceComment.getTaskId());
                }
                commentList.add(processInstanceComment);
                taskCommentListMap.put(processInstanceComment.getTaskId(),commentList);
                commentTaskDefKeyMap.put(taskInstanceName,taskCommentListMap);

            }
        }

        List<StepMsg> stepMsgList = new LinkedList<>();
        for (String taskDefinitionKey : commentTaskDefKeyMap.keySet()) {
            StepMsg stepMsg = new StepMsg();

            stepMsg.stepName = taskDefinitionKey;
            Map<String, List<Comment>> stringListMap = commentTaskDefKeyMap.get(taskDefinitionKey);
            List<SignUser> signUserList = new LinkedList<>();
            for (String taskId : stringListMap.keySet()) {
                stepMsg.taskId = taskId;

                List<Comment> commentList1 = stringListMap.get(taskId);
                Map<String,SignUser> signUserMap = new HashMap<>();
                SignUser signUser;

                for (Comment comment : commentList1) {
                    if(signUserMap.get(comment.getUserId()) == null){
                        signUser = new SignUser();
                    } else {
                        signUser = signUserMap.get(comment.getUserId());
                    }

                    signUser.userId = comment.getUserId();
                    if("comment".equals(comment.getType())){
                        signUser.comment = comment.getFullMessage();
                    } else {
                        signUser.dealSign = comment.getFullMessage();
                    }
                    signUser.dealTime = comment.getTime();
                    signUserMap.put(comment.getUserId(),signUser);
                }

                for (SignUser value : signUserMap.values()) {
                    signUserList.add(value);
                }
            }
            stepMsg.counterSignUsers =signUserList;
            stepMsgList.add(stepMsg);

        }

        return stepMsgList;
    }

    /**
     * 根据业务id和用户身份判断是否允许进行审批操作
     * @param businessKey
     * @param userId
     * @param groups
     * @return
     */
    public boolean checkApproveByBusinessKeyAndUserIdentity(String businessKey,String userId,List<String> groups){
        TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
        if(!CollectionUtils.isEmpty(groups)) {
            taskQuery.taskCandidateGroupIn(groups);
        }
        List<Task> taskList = taskQuery.active().orderByTaskId().desc().list();

        taskList = removeDuplicateTask(taskList);
        for (Task task : taskList) {
            Map stepMsgList = getStepMsgList(task.getProcessDefinitionId(), task.getProcessInstanceId(), task.getId());
            if(businessKey.equals(stepMsgList.get("businessKey"))){
                return true;
            }
        }
        return false;
    }


    public List<Task> removeDuplicateTask(List<Task> taskList){
        //洗完去重后的列表
        List<Task> list = new ArrayList<>();
        String procInstId = "";
        for (Task task : taskList) {
            if(StringUtils.isEmpty(procInstId)) {
                procInstId = task.getProcessInstanceId();
                list.add(task);
            }

            if(!procInstId.equals(task.getProcessInstanceId())) {
                list.add(task);
                procInstId = task.getProcessInstanceId();
            }
        }
        return list;
    }

    public List<HistoricTaskInstance> removeDuplicateHisTask(List<HistoricTaskInstance> taskList){
        //洗完去重后的列表
        List<HistoricTaskInstance> list = new ArrayList<>();
        String procInstId = "";
        for (HistoricTaskInstance task : taskList) {
            if(StringUtils.isEmpty(procInstId)) {
                procInstId = task.getProcessInstanceId();
                list.add(task);
            }

            if(!procInstId.equals(task.getProcessInstanceId())) {
                list.add(task);
                procInstId = task.getProcessInstanceId();
            }
        }
        return list;
    }

    public List setPageByList(List list,int pageSize,int pageNo) {
        //分页处理
        int first = -1;
        if(pageNo>0 && (pageNo-1)*pageSize<list.size()) {
            first = (pageNo-1)*pageSize;
        }
        int last = -1;
        if(pageSize*pageNo<list.size()){
            last = pageSize*pageNo;
        } else {
            last = list.size();
        }
        if(first == -1 || last == -1) {
            list = new ArrayList<>();
        } else {
            list = list.subList(first,last);
        }
        return list;
    }

}
